<?php

/**
 * 解析 SQL 文件
 */

/**
 * 加载 sql 文件为分号分割的数组，注意最后一条命令语句要以分号结尾，否则最后一条命令不会解析出来
 * 支持存储过程和函数提取，自动过滤注释
 * @param string $path 文件路径
 * @return boolean|array
 * @version 1.0 2015-5-27 Added.
 * @version 1.1 2016-9-6 修正 drop function 或 drop procedure 无法解析的问题
 */
function parseSqlStatement($lines, $routineSplitor = ';;')
{
    // $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); // 读取文件到数组
    $outlines = [];
    $lines = array_filter($lines);
    if (!$lines) {
        return $outlines;
    }
    $stmt = '';
    $isRoutine = false;
    $routineSplitorEnd = $routineSplitor[0];
    $isSkip = false; // 是否过滤批量注释
    foreach ($lines as $line) {
        $line = trim($line); // 过滤头尾空格
        if (!$line) {
            continue; // 过滤空行
        }
        if (0 === strpos($line, '/*')) { // 批量注释开始
            // 判断是否单行注释 /* ... */
            if (false === strpos($line, '*/')) {
                $isSkip = true; // 批量注释开始
            }
            continue; // 单行注释，直接跳过
        }
        if ($isSkip && (false !== strpos($line, '*/'))) { // 批量注释结束
            $isSkip = false;
            continue;
        }
        if ($isSkip) {
            continue; // 过滤批量注释
        }
        if (0 === strpos($line, '-- ')) {
            continue; // 过滤单行注释
        }
        
        $lowerline = strtolower($line);
        $lowerline = preg_replace('/[\s]+/', ' ', trim($lowerline)); // 多个空格合并成一个
        // 提取存储过程和函数
        if (!$isRoutine && 0 === strpos($lowerline, 'delimiter ' . $routineSplitor)) {
            $isRoutine = true;
            continue;
        }
        if ($isRoutine) {
            // drop 语句独立一行
            if (0 === strpos($lowerline, 'drop function ') || 0 === strpos($lowerline, 'drop procedure ')) {
                $outlines[] = $line;
                $stmt = '';
                continue;
            }
            if (0 === strpos($lowerline, 'delimiter ' . $routineSplitorEnd)) {
                $isRoutine = false;
                $outlines[] = $stmt;
                $stmt = '';
                continue;
            }
            $stmt .= $line . ' ';
            continue;
        }
        // 提取普通语句，支持一个语句拆分成很多行的写法，注意语句结束后必须以分号结尾
        $stmt .= $line . ' '; // 串联行内容要加个空格，防止 select a\rfrom table，拼凑成 select afrom table
        if (false !== strpos($line, ';') && strlen($line) == (strpos($line, ';') + 1)) {
            $outlines[] = $stmt;
            $stmt = '';
        }
    }
    // 兼容单sql语句，且没有以分号结尾的情况
    // if (!$outlines && $stmt) { // 这样写最后一条命令如果没有分号结尾会解析不出来
    if ($stmt) {
        $outlines[] = $stmt;
    }
    return $outlines;
}
